import { jest } from '@jest/globals';
import request from 'supertest';
import { io as Client } from 'socket.io-client';
import XuantuotuoMultiplayerServer from '../../server.js';
import { testUtils, mockLogger } from '../setup.js';

// 模拟所有依赖
jest.mock('../../utils/logger.js', () => mockLogger);
jest.mock('../../services/DatabaseService.js');
jest.mock('../../config/database.js', () => ({
  host: 'localhost',
  port: 3306,
  user: 'test',
  password: 'test',
  database: 'test'
}));

describe('Integration Tests - WebSocket Communication', () => {
  let server;
  let httpPort;
  let wsPort;
  let httpServer;

  beforeAll(async () => {
    // 使用随机端口避免冲突
    httpPort = 3000 + Math.floor(Math.random() * 1000);
    wsPort = 3100 + Math.floor(Math.random() * 1000);
    
    process.env.PORT = httpPort.toString();
    process.env.WS_PORT = wsPort.toString();
    process.env.NODE_ENV = 'test';

    server = new XuantuotuoMultiplayerServer();
    
    // 模拟数据库和其他服务
    server.db = {
      createRoom: jest.fn().mockResolvedValue(true),
      getRoomById: jest.fn(),
      joinRoom: jest.fn().mockResolvedValue(true),
      updatePlayerStatus: jest.fn().mockResolvedValue(true),
      close: jest.fn().mockResolvedValue()
    };
    
    await server.init();
    httpServer = server.httpServer;
    
    // 等待服务器完全启动
    await new Promise(resolve => setTimeout(resolve, 500));
  }, 30000);

  afterAll(async () => {
    if (server) {
      await server.setupGracefulShutdown();
      if (httpServer) {
        httpServer.close();
      }
    }
  }, 10000);

  describe('HTTP API Integration', () => {
    it('should respond to health check', async () => {
      const response = await request(httpServer)
        .get('/health')
        .expect(200);

      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('server');
      expect(response.body.data).toHaveProperty('version');
      expect(response.body.data).toHaveProperty('uptime');
    });

    it('should handle 404 for unknown routes', async () => {
      const response = await request(httpServer)
        .get('/unknown-route')
        .expect(404);

      expect(response.body.success).toBe(false);
      expect(response.body.error.code).toBe('NOT_FOUND');
    });

    it('should provide CORS headers', async () => {
      const response = await request(httpServer)
        .options('/health')
        .expect(204);

      expect(response.headers['access-control-allow-origin']).toBeDefined();
    });
  });

  describe('WebSocket Connection Flow', () => {
    let client1, client2, client3;
    const clients = [];

    const createClient = (port = wsPort) => {
      const client = Client(`http://localhost:${port}`, {
        transports: ['websocket'],
        forceNew: true
      });
      clients.push(client);
      return client;
    };

    afterEach(async () => {
      // 清理所有客户端连接
      for (const client of clients) {
        if (client.connected) {
          client.disconnect();
        }
      }
      clients.length = 0;
      await testUtils.waitFor(100);
    });

    it('should handle client connection and disconnection', async () => {
      return new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Connection timeout')), 5000);
        
        client1 = createClient();
        
        client1.on('connect', () => {
          expect(client1.connected).toBe(true);
          client1.disconnect();
        });

        client1.on('disconnect', () => {
          clearTimeout(timeout);
          resolve();
        });

        client1.on('connect_error', (error) => {
          clearTimeout(timeout);
          reject(error);
        });
      });
    });

    it('should handle player registration', async () => {
      return new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Registration timeout')), 5000);
        
        client1 = createClient();
        
        client1.on('connect', () => {
          client1.emit('register_player', {
            playerId: 'test-player-1',
            roomId: null
          }, (response) => {
            try {
              expect(response.success).toBe(true);
              expect(response.data.playerId).toBe('test-player-1');
              clearTimeout(timeout);
              resolve();
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          });
        });

        client1.on('connect_error', (error) => {
          clearTimeout(timeout);
          reject(error);
        });
      });
    });

    it('should handle room creation and joining flow', async () => {
      return new Promise(async (resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Room flow timeout')), 10000);
        
        try {
          client1 = createClient();
          client2 = createClient();

          // 等待两个客户端连接
          await Promise.all([
            new Promise(res => client1.on('connect', res)),
            new Promise(res => client2.on('connect', res))
          ]);

          // Player 1 创建房间
          const roomResult = await new Promise((res, rej) => {
            client1.emit('create_room', {
              roomName: 'Integration Test Room',
              playerName: 'Host Player'
            }, (response) => {
              if (response.success) res(response);
              else rej(new Error(response.error?.message || 'Create room failed'));
            });
          });

          expect(roomResult.success).toBe(true);
          expect(roomResult.data.room.name).toBe('Integration Test Room');
          const roomId = roomResult.data.room.id;

          // Player 2 加入房间
          const joinResult = await new Promise((res, rej) => {
            client2.emit('join_room', {
              roomId: roomId,
              playerName: 'Guest Player'
            }, (response) => {
              if (response.success) res(response);
              else rej(new Error(response.error?.message || 'Join room failed'));
            });
          });

          expect(joinResult.success).toBe(true);
          expect(joinResult.data.player.name).toBe('Guest Player');

          // 验证其他玩家收到加入通知
          client1.on('player_joined', (notification) => {
            expect(notification.success).toBe(true);
            expect(notification.data.player.name).toBe('Guest Player');
            clearTimeout(timeout);
            resolve();
          });

        } catch (error) {
          clearTimeout(timeout);
          reject(error);
        }
      });
    });

    it('should handle ready state and game start flow', async () => {
      return new Promise(async (resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Game start timeout')), 15000);
        
        try {
          client1 = createClient();
          client2 = createClient();
          client3 = createClient();

          // 等待所有客户端连接
          await Promise.all([
            new Promise(res => client1.on('connect', res)),
            new Promise(res => client2.on('connect', res)),
            new Promise(res => client3.on('connect', res))
          ]);

          // 创建房间
          const roomResult = await new Promise((res) => {
            client1.emit('create_room', {
              roomName: 'Game Start Test',
              playerName: 'Host'
            }, res);
          });

          const roomId = roomResult.data.room.id;

          // 其他玩家加入
          await Promise.all([
            new Promise((res) => {
              client2.emit('join_room', {
                roomId: roomId,
                playerName: 'Player2'
              }, res);
            }),
            new Promise((res) => {
              client3.emit('join_room', {
                roomId: roomId,
                playerName: 'Player3'
              }, res);
            })
          ]);

          // 玩家准备
          await Promise.all([
            new Promise((res) => {
              client2.emit('toggle_ready', { ready: true }, res);
            }),
            new Promise((res) => {
              client3.emit('toggle_ready', { ready: true }, res);
            })
          ]);

          // 模拟游戏引擎返回成功结果
          server.gameEngine.startGame = jest.fn().mockResolvedValue({
            success: true,
            data: { sessionId: 'test-session', gameState: { round: 1 } }
          });

          // 房主开始游戏
          client1.emit('start_game', (response) => {
            try {
              expect(response.success).toBe(true);
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          });

          // 监听游戏开始通知
          let notificationCount = 0;
          const handleGameStart = (notification) => {
            notificationCount++;
            if (notificationCount === 3) { // 所有三个客户端都收到通知
              expect(notification.success).toBe(true);
              expect(notification.data.sessionId).toBe('test-session');
              clearTimeout(timeout);
              resolve();
            }
          };

          client1.on('game_started', handleGameStart);
          client2.on('game_started', handleGameStart);
          client3.on('game_started', handleGameStart);

        } catch (error) {
          clearTimeout(timeout);
          reject(error);
        }
      });
    });

    it('should handle disconnection and reconnection', async () => {
      return new Promise(async (resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Reconnection timeout')), 8000);
        
        try {
          client1 = createClient();
          
          await new Promise(res => client1.on('connect', res));

          // 注册玩家
          await new Promise((res) => {
            client1.emit('register_player', {
              playerId: 'reconnect-test-player'
            }, res);
          });

          // 创建房间
          const roomResult = await new Promise((res) => {
            client1.emit('create_room', {
              roomName: 'Reconnection Test',
              playerName: 'TestPlayer'
            }, res);
          });

          const roomId = roomResult.data.room.id;

          // 断开连接
          client1.disconnect();
          await testUtils.waitFor(100);

          // 重新连接
          client1 = createClient();
          await new Promise(res => client1.on('connect', res));

          // 重新注册同一个玩家
          client1.emit('register_player', {
            playerId: 'reconnect-test-player',
            roomId: roomId
          }, (response) => {
            try {
              expect(response.success).toBe(true);
              expect(response.data.playerId).toBe('reconnect-test-player');
              clearTimeout(timeout);
              resolve();
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          });

        } catch (error) {
          clearTimeout(timeout);
          reject(error);
        }
      });
    });

    it('should handle ping/pong heartbeat with formatted response', async () => {
      return new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Ping timeout')), 3000);
        
        client1 = createClient();
        
        client1.on('connect', () => {
          client1.emit('ping', (response) => {
            try {
              expect(response.success).toBe(true);
              expect(response.data.timestamp).toBeDefined();
              expect(response.message).toBe('pong');
              clearTimeout(timeout);
              resolve();
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          });
        });
      });
    });

    it('should handle error scenarios gracefully', async () => {
      return new Promise(async (resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Error handling timeout')), 5000);
        
        try {
          client1 = createClient();
          await new Promise(res => client1.on('connect', res));

          // 测试无效的房间创建
          client1.emit('create_room', {
            roomName: '', // 无效的房间名
            playerName: 'TestPlayer'
          }, (response) => {
            try {
              expect(response.success).toBe(false);
              expect(response.error).toBeDefined();
              expect(response.error.code).toBe('CREATE_FAILED');
              clearTimeout(timeout);
              resolve();
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          });

        } catch (error) {
          clearTimeout(timeout);
          reject(error);
        }
      });
    });
  });

  describe('Game Flow Integration', () => {
    let clients = [];
    let roomId;

    const createGameSession = async () => {
      // 创建三个客户端
      for (let i = 0; i < 3; i++) {
        const client = Client(`http://localhost:${wsPort}`, {
          transports: ['websocket'],
          forceNew: true
        });
        clients.push(client);
        await new Promise(res => client.on('connect', res));
      }

      // 创建房间
      const roomResult = await new Promise((res) => {
        clients[0].emit('create_room', {
          roomName: 'Game Integration Test',
          playerName: 'Host'
        }, res);
      });

      roomId = roomResult.data.room.id;

      // 其他玩家加入
      await Promise.all([
        new Promise((res) => {
          clients[1].emit('join_room', {
            roomId: roomId,
            playerName: 'Player2'
          }, res);
        }),
        new Promise((res) => {
          clients[2].emit('join_room', {
            roomId: roomId,
            playerName: 'Player3'
          }, res);
        })
      ]);

      // 设置准备状态
      await Promise.all([
        new Promise((res) => clients[1].emit('toggle_ready', { ready: true }, res)),
        new Promise((res) => clients[2].emit('toggle_ready', { ready: true }, res))
      ]);

      return roomId;
    };

    afterEach(async () => {
      for (const client of clients) {
        if (client.connected) {
          client.disconnect();
        }
      }
      clients.length = 0;
      await testUtils.waitFor(100);
    });

    it('should handle complete game initialization', async () => {
      // 模拟游戏引擎
      server.gameEngine.startGame = jest.fn().mockResolvedValue({
        success: true,
        data: {
          sessionId: 'game-session-123',
          gameState: {
            players: [
              { id: 'host-id', name: 'Host', cardCount: 8 },
              { id: 'player2-id', name: 'Player2', cardCount: 8 },
              { id: 'player3-id', name: 'Player3', cardCount: 8 }
            ],
            currentPlayerIndex: 0,
            currentRound: 1
          }
        }
      });

      const roomId = await createGameSession();

      return new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Game init timeout')), 5000);

        let gameStartNotifications = 0;
        const handleGameStart = (notification) => {
          gameStartNotifications++;
          if (gameStartNotifications === 3) {
            try {
              expect(notification.success).toBe(true);
              expect(notification.data.sessionId).toBe('game-session-123');
              expect(notification.data.gameState.players).toHaveLength(3);
              clearTimeout(timeout);
              resolve();
            } catch (error) {
              clearTimeout(timeout);
              reject(error);
            }
          }
        };

        clients.forEach(client => {
          client.on('game_started', handleGameStart);
        });

        // 开始游戏
        clients[0].emit('start_game', (response) => {
          if (!response.success) {
            clearTimeout(timeout);
            reject(new Error(response.error?.message || 'Start game failed'));
          }
        });
      });
    });

    it('should handle game actions flow', async () => {
      const testCards = [{ id: 'card-1', rank: '10', suit: 'hearts' }];
      
      // 模拟游戏引擎响应
      server.gameEngine.playCards = jest.fn().mockResolvedValue({
        success: true,
        data: {
          gameState: {
            roundCards: [{ player: 'host-id', cards: testCards }],
            currentPlayerIndex: 1
          }
        }
      });

      const roomId = await createGameSession();

      return new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('Game action timeout')), 5000);

        // 监听游戏状态更新
        clients[1].on('game_state_update', (update) => {
          try {
            expect(update.success).toBe(true);
            expect(update.data.gameState.roundCards).toHaveLength(1);
            expect(update.data.gameState.currentPlayerIndex).toBe(1);
            clearTimeout(timeout);
            resolve();
          } catch (error) {
            clearTimeout(timeout);
            reject(error);
          }
        });

        // 注册玩家并出牌
        clients[0].emit('register_player', { playerId: 'host-id', roomId }, () => {
          clients[0].emit('play_cards', { cards: testCards }, (response) => {
            if (!response.success) {
              clearTimeout(timeout);
              reject(new Error(response.error?.message || 'Play cards failed'));
            }
          });
        });
      });
    });
  });
});